#include "../StdInc.h"

#include <boost/format.hpp>
using namespace boost;

namespace GSTrader
{
	namespace TradeStrategy
	{
		CPortfolioPosition::CPortfolioPosition(CPortfolio* pPortfolio, CExecutionReport& report) :
			CPositionBase(), m_pPortfolio(pPortfolio), m_dQty(0), m_dLongQty(0), m_dShortQty(0), m_dNetQty(0)
		{
			m_nProviderId = report.m_nProviderId;
			m_nInstrumentId = report.m_nInstrumentId;

			m_nOpenTime  = report.m_time;
			m_dOpenPrice = report.m_dLastPrice;
			m_dOpenQty   = report.m_dLastQty;

			CInstrument* pInstrument = pPortfolio->m_pFramework->GetInstrumentById(m_nInstrumentId);
			if (pInstrument)
			{
				m_strInstrumentId = pInstrument->m_strSymbol;
				m_strExchangeId = pInstrument->m_strExchangeID;
			}

			Add(report);
		}

		CPortfolioPosition::CPortfolioPosition(CPortfolio* pPortfolio, CPosition& position) :
			CPositionBase(), m_pPortfolio(pPortfolio), m_dQty(0), m_dLongQty(0), m_dShortQty(0), m_dNetQty(0)
		{
			m_nProviderId = position.m_nProviderId;
			m_nInstrumentId   = position.m_nInstrumentId;
			m_strInstrumentId = position.m_strInstrumentId;
			m_strExchangeId   = position.m_strExchangeId;

			m_nOpenTime  = position.GetPositionTime();
			m_dOpenPrice = position.m_dLastSettlementPrice;
			m_dOpenQty   = position.m_nTotalPosition;

			Add(position);
		}

		CPortfolioPosition::CPortfolioPosition(CPortfolio* pPortfolio, int nInstrumentId, int nProviderId) : CPositionBase(), m_pPortfolio(pPortfolio),
			m_dQty(0), m_dLongQty(0), m_dShortQty(0), m_dNetQty(0), m_nOpenTime(0), m_dOpenPrice(0), m_dOpenQty(0)
		{
			m_nProviderId = nProviderId;
			m_nInstrumentId = nInstrumentId;

			CInstrument* pInstrument = pPortfolio->m_pFramework->GetInstrumentById(nInstrumentId);
			if (pInstrument)
			{
				m_strInstrumentId = pInstrument->m_strSymbol;
				m_strExchangeId = pInstrument->m_strExchangeID;
			}
		}

		CPortfolioPosition::~CPortfolioPosition()
		{

		}

		CPortfolioPosition& CPortfolioPosition::operator = (const CPortfolioPosition& r)
		{
			m_nProviderId		= r.m_nProviderId;
			m_nInstrumentId = r.m_nInstrumentId;
			m_strInstrumentId = r.m_strInstrumentId;
			m_strExchangeId	  = r.m_strExchangeId;
			m_nLongShort = r.m_nLongShort;
			m_dQty  = r.m_dQty;
			m_dLongQty  = r.m_dLongQty;
			m_dShortQty = r.m_dShortQty;
			m_dNetQty  = r.m_dNetQty;

			m_nOpenTime  = r.m_nOpenTime;
			m_dOpenPrice = r.m_dOpenPrice;
			m_dOpenQty   = r.m_dOpenQty;

			m_vTrade = r.m_vTrade;

			m_pPortfolio = r.m_pPortfolio;
			return *this;
		}

		void CPortfolioPosition::Add(CPosition& position)
		{
			if (position.m_nTotalPosition <= 0)
				return;

			if (position.m_nLongShort == posLong || position.m_nLongShort == posNet)
			{
				m_dLongQty += position.m_nTotalPosition;
			}
			else
			{
				m_dShortQty += position.m_nTotalPosition;
			}

			m_nLongShort = m_dLongQty > m_dShortQty ? posLong : posShort;
			m_dNetQty = m_dLongQty - m_dShortQty;
			m_dQty = abs(m_dNetQty);
		}

#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
		void CPortfolioPosition::Add(CExecutionReport& report)
		{
			m_vTrade.push_back(report.m_nTradeId);

			assert(report.m_nOpenClose != ocAutoOpenClose);
			if (report.m_nOpenClose == ocOpen)
			{
				if (report.m_nSide == osBuy)
				{
					m_dLongQty += report.m_dLastQty;
				}
				else
				{
					m_dShortQty += report.m_dLastQty;
				}
			}
			else 
			{
				if (report.m_nSide == osBuy)
				{
					m_dShortQty -= report.m_dLastQty;
					m_dShortQty = max(m_dShortQty, 0);

				}
				else if (report.m_nSide == osSell)
				{
					m_dLongQty -= report.m_dLastQty;
					m_dLongQty = max(m_dLongQty, 0);
				}
				else
				{
					//assert(false);
				}
			}

			m_nLongShort = m_dLongQty > m_dShortQty ? posLong : posShort;
			m_dNetQty = m_dLongQty - m_dShortQty;
			m_dQty    = abs(m_dNetQty);
		}

		CStrategyBase* CPortfolioPosition::GetStrategy()
		{
			return m_pPortfolio->m_pStrategy;
		}

		string CPortfolioPosition::ToString()
		{
			format fmt(g_language == slChinese ? Chinese::c_szFmt48 : English::c_szFmt48);
			fmt % m_strInstrumentId;
			fmt % m_dQty;
			fmt % m_dLongQty;
			fmt % m_dShortQty;
			fmt % m_dNetQty;

			return fmt.str();
		}
	}
}